﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Net.SamuelChen.SharpTweet {
    internal static class HttpRequestMethods {
        public const string GET = "GET";
        public const string PUT = "PUT";
        public const string POST = "POST";
        public const string DELETE = "DELETE";
    }

    public class HtmlLink {
        public string Value = string.Empty;
        public string Text = string.Empty;
        public string URI = string.Empty;
    }

    public class Utility {

        #region Network

        public const int DEFAULT_TIMEOUT = 30000; // 30 seconds

        /// <summary>
        /// Create a http request by given parameters
        /// </summary>
        /// <param name="id">The user id for authorizaion.</param>
        /// <param name="pwd">The password for authorizaion.</param>
        /// <param name="uri">The uri string to request.</param>
        /// <param name="method">The reqest method such as GET, PUT, POST or DELETE.</param>
        /// <param name="timeout">The timeout of the request (ms).</param>
        /// <param name="useProxy">Whether this request will connect via proxy.</param>
        /// <param name="proxy">The proxy address string.</param>
        /// <returns>A HttpWebRequest object.</returns>
        public static HttpWebRequest CreateRequest(string id, string pwd,
            string uri, string method, int timeout,
            bool useProxy, string proxy) {

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);

            if (request != null) {
                request.Timeout = timeout > 0 ? timeout : DEFAULT_TIMEOUT;
                request.Method = method;
                request.ContentType = "application/x-www-form-urlencoded";
                request.Referer = "http://www.SamuelChen.net";
                request.UserAgent = "Samuel's twitter client";
                if (useProxy)
                    request.Proxy = new WebProxy(proxy, false);

                request.Credentials = new NetworkCredential(id, pwd);

                // to solve issue - Twitter Dishing Out 417 - Expectation Failed to .Net Clients
                // http://blogs.msdn.com/shitals/archive/2008/12/27/9254245.aspx
                request.ServicePoint.Expect100Continue = false;
            }

            return request;
        }

        /// <summary>
        /// Get response content as string.
        /// </summary>
        /// <param name="request">Constructed web request.</param>
        /// <returns>Response string.</returns>
        /// <exception cref="System.TimeoutException">System.TimeoutException</exception>
        /// <exception cref="Net.SamuelChen.SharpTweet.UnauthorizedAccessException">Net.SamuelChen.SharpTweet.UnauthorizedException</exception>
        /// <exception cref="Net.SamuelChen.SharpTweet.ReachedLimitationException">Net.SamuelChen.SharpTweet.ReachedLimitationException</exception>
        /// <exception cref="Net.SamuelChen.SharpTweet.PageNotFoundException">Net.SamuelChen.SharpTweet.PageNotFoundException</exception>
        /// <exception cref="System.Exception">System.Exception</exception>
        public static string GetResponseContent(WebRequest request) {
            string content = string.Empty;

            try {
                WebResponse response = request.GetResponse();
                using (Stream responseStream = response.GetResponseStream()) {
                    using (StreamReader reader = new StreamReader(responseStream)) {
                        content = reader.ReadToEnd();
                    }
                }
            } catch (WebException ex) {
                Trace.TraceError(ex.ToString());
                request.Abort();

#if DEBUG
                Debug.WriteLine(ex.Status);

                if (ex.Response != null && ex.Response.Headers != null) {
                    Debug.WriteLine("^^^^^^^^^^^^^^^^");
                    for (int i = 0; i < ex.Response.Headers.Count; i++) {
                        Debug.WriteLine(ex.Response.Headers.Keys[i] + " - " + ex.Response.Headers.Get(i));
                    }
                }
                Debug.WriteLine("^^^^^^^^^^^^^^");
                if (ex.Data != null) {
                    System.Collections.IDictionaryEnumerator iter = ex.Data.GetEnumerator();
                    while (iter.MoveNext()) {
                        Debug.WriteLine(iter.Key + " - " + iter.Value);
                    }
                }
#endif

                switch (ex.Status) {
                    case WebExceptionStatus.Timeout:
                        throw new TimeoutException(ex.Message, ex);
                        break;
                    case WebExceptionStatus.ProtocolError:
                        string status = ex.Response.Headers["Status"];
                        if (null != status)
                            if (status.Contains("401")) {
                                throw new UnauthorizedException("You are not authorized.", ex);
                            } else if (status.Contains("403")) {
                                throw new ReachedLimitationException("You are about to hit the update limitaion.", ex);
                            } else if (status.Contains("404")) {
                                throw new PageNotFoundException("The resource you requested is not found.", ex);
                            }

                        break;
                    default:
                        break;
                }

                request.Abort();
                throw ex;

            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
#if DEBUG
                request.Abort();
                throw ex;
#endif
            }
            finally {
                request.Abort();
            }
            return content;
        }

        #endregion

        #region
        
        /// <summary>
        /// Parse a HTML link string (HTML a tag) to a instance of struct HtmlLink.
        /// </summary>
        /// <param name="linkHtmlStr">The html string of the </param>
        /// <returns>The created HtmlLink instance.</returns>
        public static HtmlLink ParseHtmlLink(string linkHtmlStr) {
            //htmlLink = "<a href=\"http://www.SamuelChen.net/\" target=\"_blank\">#Twitter</a>";
            HtmlLink link = null;
            string expr = "<a href=\""
              + "(?<uri>[^\"]+)"        // the hyperlink data
              + "\"(?<attrib>[^>]*)>"   // end quote, then skip to end of tag
              + "(?<text>[^<]+)"        // name is data up to next tag
              + "</a>";                 // end a tag
            Regex r = new Regex(expr);
            Match m = r.Match(linkHtmlStr);
            if (m.Success) {
                link = new HtmlLink();
                link.Value = m.Value;
                link.Text = m.Groups["text"].Value;
                link.URI = m.Groups["uri"].Value;
             }
            return link;
        }


        public static DateTime ParseDateTime(string date) {
            DateTime dt = DateTime.MinValue;

            string expr = @"(?x:)(?m:)(?i:)
                (?<w>Mon|Tue|Wen|Thu|Fri|Sat|Sun)\W
                (?<m>Jan|Feb|Mar|Apr|May|Jun|Jul|Aut|Sep|Oct|Nov|Dec)\W
                (?<d>\d{1,2})\W
                (?<t>\d{2}:\d{2}:\d{2})\W
                (?<gmt>\S+)\W
                (?<y>\d{4})";
            string replace = @"${w}, ${d} ${m} ${y} ${t} GMT";
            
            string s = Regex.Replace(date, expr, replace, 
                RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
            
            try {
                dt = DateTime.Parse(s, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
            } catch { }

            return dt;
        }

        #endregion
    }
}
